using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using EnvDTE;
using HQLAddin.ConfigurationInspector;
using HQLAddin.Tests.Configuration.Util;
using Moq;
using NUnit.Framework;
using SharpTestsEx;

namespace HQLAddin.Tests.Configuration
{
	[TestFixture]
	public class PathProviderTests
	{
		[Test]
		public void CanFindPaths()
		{
		    
			//var projects = new Mock<IEnumerable<Project>>();//.As<Projects>();
			var list = new ProjectsList { CreateMockedProject("MyDal"), CreateMockedProject("MyBus"), CreateMockedProject("MyDomain") };

		    var dte = new Mock<DTE>();
		    dte.Setup(d => d.Solution.Projects).Returns(list);
			
		    var pathProvider = new PathProvider(dte.Object);
			var expected = new[]
			               	{
			               		@"C:\MyFoo\Bar\MyDal\Bin\Debug",
			               		@"C:\MyFoo\Bar\MyBus\Bin\Debug",
			               		@"C:\MyFoo\Bar\MyDomain\Bin\Debug"
			               	};

			pathProvider.FindPaths()
				.Should()
				.Have.SameValuesAs(expected);
		}

		[Test]
		public void WhenProjectHasNullPropertiesThenDoesNotInclude()
		{
			var failingProject = new Mock<Project>();
			failingProject.Setup(p => p.Properties).Returns((Properties)null);
			var list = new ProjectsList { failingProject.Object, CreateMockedProject("MyDomain") };

			var dte = new Mock<DTE>();
			dte.Setup(d => d.Solution.Projects).Returns(list);

			var pathProvider = new PathProvider(dte.Object);
			pathProvider.FindPaths().Should().Contain(@"C:\MyFoo\Bar\MyDomain\Bin\Debug").And.Have.Count.EqualTo(1);

		}

		[Test]
		public void WhenProjectHasNullPropertiesThenDoesNotThrow()
		{
			var nullPathProject = new Mock<Project>();
			nullPathProject.Setup(p => p.Properties).Returns((Properties)null);
			var list = new ProjectsList { nullPathProject.Object, CreateMockedProject("MyDomain") };

			var dte = new Mock<DTE>();
			dte.Setup(d => d.Solution.Projects).Returns(list);

			var pathProvider = new PathProvider(dte.Object);
			pathProvider.Executing(pp => pp.FindPaths().ToArray()).NotThrows();
		}

		[Test]
		public void WhenProjectIsSolutionFolderThenReturnPathOfNestedProjects()
		{
			var project = new Mock<Project>();
			project.Setup(p => p.ProjectItems).Returns(new ProjectItemList { CreateMockedProject("MyDomain").ToProjectItem() });	

			var list = new ProjectsList { project.Object };

			var dte = new Mock<DTE>();
			dte.Setup(d => d.Solution.Projects).Returns(list);

			var pathProvider = new PathProvider(dte.Object);
			pathProvider.FindPaths().Should().Contain(@"C:\MyFoo\Bar\MyDomain\Bin\Debug");
		}


		[Test]
		public void BugWhenProjectItemDoesNotHaveFullPathProperty()
		{

			//var projects = new Mock<IEnumerable<Project>>();//.As<Projects>();
			var list = new ProjectsList { CreateMockedProjectWithoutFullPath("MyDal"), CreateMockedProject("MyBus"), CreateMockedProject("MyDomain") };

			var dte = new Mock<DTE>();
			dte.Setup(d => d.Solution.Projects).Returns(list);

			var pathProvider = new PathProvider(dte.Object);
			var expected = new[]
			               	{

			               		@"C:\MyFoo\Bar\MyBus\Bin\Debug",
			               		@"C:\MyFoo\Bar\MyDomain\Bin\Debug"
			               	};

			pathProvider.FindPaths()
				.Should()
				.Have.SameValuesAs(expected).And.Have.Count.EqualTo(2);
		}

		private static Project CreateMockedProject(string projectName)
		{
			var project = new Mock<Project>();
			project.Setup(p => p.UniqueName).Returns(projectName);
			project.Setup(p => p.ConfigurationManager.ActiveConfiguration.Properties.Item("OutputPath").Value).Returns(@"Bin\Debug\");
			var fullPath = string.Format(@"C:\MyFoo\Bar\{0}\", projectName);
			project.Setup(p => p.Properties).Returns(new PropertiesList {Mock.Of<Property>(p => p.Name == "FullPath" && p.Value == fullPath)});
			return project.Object;
		}

		private static Project CreateMockedProjectWithoutFullPath(string projectName)
		{
			var project = new Mock<Project>();
			project.Setup(p => p.UniqueName).Returns(projectName);
			project.Setup(p => p.ConfigurationManager.ActiveConfiguration.Properties.Item("OutputPath").Value).Returns(@"Bin\Debug\");
			project.Setup(p => p.Properties).Returns(new PropertiesList());
			return project.Object;
		}


		
	}
}